home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / amitcp / netinet / ip_output.c < prev    next >
C/C++ Source or Header  |  1993-08-12  |  17KB  |  667 lines

  1. RCS_ID_C="$Id: ip_output.c,v 1.9 1993/06/04 11:16:15 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * HISTORY
  8.  * $Log: ip_output.c,v $
  9.  * Revision 1.9  1993/06/04  11:16:15  jraja
  10.  * Fixes for first public release.
  11.  *
  12.  * Revision 1.8  1993/05/17  00:16:44  ppessi
  13.  * Changed RCS version. Added rcsid.
  14.  *
  15.  * Revision 1.7  1993/04/24  23:22:09  jraja
  16.  * Removed #ifdef NOALIGN, now using straight structure copies.
  17.  *
  18.  * Revision 1.6  93/04/24  22:51:54  22:51:54  jraja (Jarno Tapio Rajahalme)
  19.  * Removed #ifdef USECLUSTERS (now using clusters always)
  20.  * 
  21.  * Revision 1.5  93/04/11  22:26:45  22:26:45  jraja (Jarno Tapio Rajahalme)
  22.  * Added STKARGFUN to protocol input & output functions (if used in protosw).
  23.  * 
  24.  * Revision 1.4  93/04/05  19:06:11  19:06:11  jraja (Jarno Tapio Rajahalme)
  25.  * Changed storage of the spl functions  return values to type spl_t.
  26.  * Added include for conf.h to every .c file.
  27.  * 
  28.  * Revision 1.3  93/03/22  16:59:15  16:59:15  jraja (Jarno Tapio Rajahalme)
  29.  * Changed bcopy()s and bzero()s with word aligned pointers to
  30.  * aligned_b(copy|zero) ar aligned_b(copy|zero)_const. The latter is for calls
  31.  * in which the size is constant.
  32.  * These can be disabled by defining NOALIGN.
  33.  *  Converted bcopys doing structure copies (on aligned pointers) to structure
  34.  * assignments, since at least SASC produces better code with assignment.
  35.  * 
  36.  * Revision 1.2  93/02/26  09:22:42  09:22:42  jraja (Jarno Tapio Rajahalme)
  37.  * Made this compile with ANSI C (added prototypes).
  38.  * Commented out ovbcopys define to bcopy.
  39.  * Casted ifp->if_mtu to u_short in comparison with another u_short.
  40.  * Commented out mbuf cluster dependant code (with #ifdef USECLUSTERS), since 
  41.  * clusters are not implemented (yet).
  42.  * 
  43.  * Revision 1.1  92/11/17  16:29:50  16:29:50  jraja (Jarno Tapio Rajahalme)
  44.  * Initial revision
  45.  *
  46.  */
  47.  
  48. /*
  49.  * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
  50.  * All rights reserved.
  51.  *
  52.  * Redistribution and use in source and binary forms, with or without
  53.  * modification, are permitted provided that the following conditions
  54.  * are met:
  55.  * 1. Redistributions of source code must retain the above copyright
  56.  *    notice, this list of conditions and the following disclaimer.
  57.  * 2. Redistributions in binary form must reproduce the above copyright
  58.  *    notice, this list of conditions and the following disclaimer in the
  59.  *    documentation and/or other materials provided with the distribution.
  60.  * 3. All advertising materials mentioning features or use of this software
  61.  *    must display the following acknowledgement:
  62.  *    This product includes software developed by the University of
  63.  *    California, Berkeley and its contributors.
  64.  * 4. Neither the name of the University nor the names of its contributors
  65.  *    may be used to endorse or promote products derived from this software
  66.  *    without specific prior written permission.
  67.  *
  68.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  69.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  70.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  71.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  72.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  73.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  74.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  75.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  76.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  77.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  78.  * SUCH DAMAGE.
  79.  *
  80.  *    @(#)ip_output.c    7.23 (Berkeley) 11/12/90
  81.  */
  82.  
  83. #include <conf.h>
  84.  
  85. #include <sys/param.h>
  86. #include <sys/systm.h>
  87. #include <sys/malloc.h>
  88. #include <sys/mbuf.h>
  89. #include <sys/errno.h>
  90. #include <sys/protosw.h>
  91. #include <sys/socket.h>
  92. #include <sys/socketvar.h>
  93. #include <sys/synch.h>
  94.  
  95. #include <net/if.h>
  96. #include <net/route.h>
  97.  
  98. #include <netinet/in.h>
  99. #include <netinet/in_systm.h>
  100. #include <netinet/ip.h>
  101. #include <netinet/in_pcb.h>
  102. #include <netinet/in_var.h>
  103. #include <netinet/ip_var.h>
  104.  
  105. #include <netinet/ip_output_protos.h>
  106. #include <netinet/in_cksum_protos.h>
  107. #include <netinet/in_protos.h>
  108.  
  109. #ifdef vax
  110. #include <machine/mtpr.h>
  111. #endif
  112.  
  113. #ifndef AMITCP
  114. #define ovbcopy bcopy
  115. #endif
  116.  
  117. struct mbuf *ip_insertoptions();
  118.  
  119. /*
  120.  * IP output.  The packet in mbuf chain m contains a skeletal IP
  121.  * header (with len, off, ttl, proto, tos, src, dst).
  122.  * The mbuf chain containing the packet will be freed.
  123.  * The mbuf opt, if present, will not be freed.
  124.  */
  125. int STKARGFUN
  126. ip_output(m0, opt, ro, flags)
  127.     struct mbuf *m0;
  128.     struct mbuf *opt;
  129.     struct route *ro;
  130.     int flags;
  131. {
  132.     register struct ip *ip, *mhip;
  133.     register struct ifnet *ifp;
  134.     register struct mbuf *m = m0;
  135.     register int hlen = sizeof (struct ip);
  136.     int len, off, error = 0;
  137.     struct route iproute;
  138.     struct sockaddr_in *dst;
  139.     struct in_ifaddr *ia;
  140.  
  141. #if    DIAGNOSTIC
  142.     if ((m->m_flags & M_PKTHDR) == 0)
  143.         panic("ip_output no HDR");
  144. #endif
  145.     if (opt) {
  146.         m = ip_insertoptions(m, opt, &len);
  147.         hlen = len;
  148.     }
  149.     ip = mtod(m, struct ip *);
  150.     /*
  151.      * Fill in IP header.
  152.      */
  153.     if ((flags & IP_FORWARDING) == 0) {
  154.         ip->ip_v = IPVERSION;
  155.         ip->ip_off &= IP_DF;
  156.         ip->ip_id = htons(ip_id++);
  157.         ip->ip_hl = hlen >> 2;
  158.     } else {
  159.         hlen = ip->ip_hl << 2;
  160.         ipstat.ips_localout++;
  161.     }
  162.     /*
  163.      * Route packet.
  164.      */
  165.     if (ro == 0) {
  166.         ro = &iproute;
  167.         aligned_bzero_const((caddr_t)ro, sizeof (*ro));
  168.     }
  169.     dst = (struct sockaddr_in *)&ro->ro_dst;
  170.     /*
  171.      * If there is a cached route,
  172.      * check that it is to the same destination
  173.      * and is still up.  If not, free it and try again.
  174.      */
  175.     if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
  176.        dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
  177.         RTFREE(ro->ro_rt);
  178.         ro->ro_rt = (struct rtentry *)0;
  179.     }
  180.     if (ro->ro_rt == 0) {
  181.         dst->sin_family = AF_INET;
  182.         dst->sin_len = sizeof(*dst);
  183.         dst->sin_addr = ip->ip_dst;
  184.     }
  185.     /*
  186.      * If routing to interface only,
  187.      * short circuit routing lookup.
  188.      */
  189.     if (flags & IP_ROUTETOIF) {
  190.  
  191.         ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
  192.         if (ia == 0)
  193.             ia = in_iaonnetof(in_netof(ip->ip_dst));
  194.         if (ia == 0) {
  195.             error = ENETUNREACH;
  196.             goto bad;
  197.         }
  198.         ifp = ia->ia_ifp;
  199.     } else {
  200.         if (ro->ro_rt == 0)
  201.             rtalloc(ro);
  202.         if (ro->ro_rt == 0) {
  203.             error = EHOSTUNREACH;
  204.             goto bad;
  205.         }
  206.         ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa;
  207.         ifp = ro->ro_rt->rt_ifp;
  208.         ro->ro_rt->rt_use++;
  209.         if (ro->ro_rt->rt_flags & RTF_GATEWAY)
  210.             dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
  211.     }
  212. #ifndef notdef
  213.     /*
  214.      * If source address not specified yet, use address
  215.      * of outgoing interface.
  216.      */
  217.     if (ip->ip_src.s_addr == INADDR_ANY)
  218.         ip->ip_src = IA_SIN(ia)->sin_addr;
  219. #endif
  220.     /*
  221.      * Look for broadcast address and
  222.      * and verify user is allowed to send
  223.      * such a packet.
  224.      */
  225.     if (in_broadcast(dst->sin_addr)) {
  226.         if ((ifp->if_flags & IFF_BROADCAST) == 0) {
  227.             error = EADDRNOTAVAIL;
  228.             goto bad;
  229.         }
  230.         if ((flags & IP_ALLOWBROADCAST) == 0) {
  231.             error = EACCES;
  232.             goto bad;
  233.         }
  234.         /* don't allow broadcast messages to be fragmented */
  235.         if ((u_short)ip->ip_len > (u_short)ifp->if_mtu) {
  236.             error = EMSGSIZE;
  237.             goto bad;
  238.         }
  239.         m->m_flags |= M_BCAST;
  240.     }
  241.  
  242.     /*
  243.      * If small enough for interface, can just send directly.
  244.      */
  245.     if ((u_short)ip->ip_len <= (u_short)ifp->if_mtu) {
  246.         ip->ip_len = htons((u_short)ip->ip_len);
  247.         ip->ip_off = htons((u_short)ip->ip_off);
  248.         ip->ip_sum = 0;
  249.         ip->ip_sum = in_cksum(m, hlen);
  250.         error = (*ifp->if_output)(ifp, m,
  251.                 (struct sockaddr *)dst, ro->ro_rt);
  252.         goto done;
  253.     }
  254.     ipstat.ips_fragmented++;
  255.     /*
  256.      * Too large for interface; fragment if possible.
  257.      * Must be able to put at least 8 bytes per fragment.
  258.      */
  259.     if (ip->ip_off & IP_DF) {
  260.         error = EMSGSIZE;
  261.         goto bad;
  262.     }
  263.     len = (ifp->if_mtu - hlen) &~ 7;
  264.     if (len < 8) {
  265.         error = EMSGSIZE;
  266.         goto bad;
  267.     }
  268.  
  269.     {
  270.     int mhlen, firstlen = len;
  271.     struct mbuf **mnext = &m->m_nextpkt;
  272.  
  273.     /*
  274.      * Loop through length of segment after first fragment,
  275.      * make new header and copy data of each part and link onto chain.
  276.      */
  277.     m0 = m;
  278.     mhlen = sizeof (struct ip);
  279.     for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
  280.         MGETHDR(m, M_DONTWAIT, MT_HEADER);
  281.         if (m == 0) {
  282.             error = ENOBUFS;
  283.             goto sendorfree;
  284.         }
  285.         m->m_data += max_linkhdr;
  286.         mhip = mtod(m, struct ip *);
  287.         *mhip = *ip;
  288.         if (hlen > sizeof (struct ip)) {
  289.             mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
  290.             mhip->ip_hl = mhlen >> 2;
  291.         }
  292.         m->m_len = mhlen;
  293.         mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
  294.         if (ip->ip_off & IP_MF)
  295.             mhip->ip_off |= IP_MF;
  296.         if (off + len >= (u_short)ip->ip_len)
  297.             len = (u_short)ip->ip_len - off;
  298.         else
  299.             mhip->ip_off |= IP_MF;
  300.         mhip->ip_len = htons((u_short)(len + mhlen));
  301.         m->m_next = m_copy(m0, off, len);
  302.         if (m->m_next == 0) {
  303.             error = ENOBUFS;    /* ??? */
  304.             goto sendorfree;
  305.         }
  306.         m->m_pkthdr.len = mhlen + len;
  307.         m->m_pkthdr.rcvif = (struct ifnet *)0;
  308.         mhip->ip_off = htons((u_short)mhip->ip_off);
  309.         mhip->ip_sum = 0;
  310.         mhip->ip_sum = in_cksum(m, mhlen);
  311.         *mnext = m;
  312.         mnext = &m->m_nextpkt;
  313.         ipstat.ips_ofragments++;
  314.     }
  315.     /*
  316.      * Update first fragment by trimming what's been copied out
  317.      * and updating header, then send each fragment (in order).
  318.      */
  319.     m = m0;
  320.     m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
  321.     m->m_pkthdr.len = hlen + firstlen;
  322.     ip->ip_len = htons((u_short)m->m_pkthdr.len);
  323.     ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
  324.     ip->ip_sum = 0;
  325.     ip->ip_sum = in_cksum(m, hlen);
  326. sendorfree:
  327.     for (m = m0; m; m = m0) {
  328.         m0 = m->m_nextpkt;
  329.         m->m_nextpkt = 0;
  330.         if (error == 0)
  331.             error = (*ifp->if_output)(ifp, m,
  332.                 (struct sockaddr *)dst, ro->ro_rt);
  333.         else
  334.             m_freem(m);
  335.     }
  336.     }
  337. done:
  338.     if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
  339.         RTFREE(ro->ro_rt);
  340.     return (error);
  341. bad:
  342.     m_freem(m0);
  343.     goto done;
  344. }
  345.  
  346. /*
  347.  * Insert IP options into preformed packet.
  348.  * Adjust IP destination as required for IP source routing,
  349.  * as indicated by a non-zero in_addr at the start of the options.
  350.  */
  351. struct mbuf *
  352. ip_insertoptions(m, opt, phlen)
  353.     register struct mbuf *m;
  354.     struct mbuf *opt;
  355.     int *phlen;
  356. {
  357.     register struct ipoption *p = mtod(opt, struct ipoption *);
  358.     struct mbuf *n;
  359.     register struct ip *ip = mtod(m, struct ip *);
  360.     unsigned optlen;
  361.  
  362.     optlen = opt->m_len - sizeof(p->ipopt_dst);
  363.     if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
  364.         return (m);        /* XXX should fail */
  365.     if (p->ipopt_dst.s_addr)
  366.         ip->ip_dst = p->ipopt_dst;
  367.     if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
  368.         MGETHDR(n, M_DONTWAIT, MT_HEADER);
  369.         if (n == 0)
  370.             return (m);
  371.         n->m_pkthdr.len = m->m_pkthdr.len + optlen;
  372.         m->m_len -= sizeof(struct ip);
  373.         m->m_data += sizeof(struct ip);
  374.         n->m_next = m;
  375.         m = n;
  376.         m->m_len = optlen + sizeof(struct ip);
  377.         m->m_data += max_linkhdr;
  378.         *mtod(m, struct ip *) = *ip;
  379.     } else {
  380.         m->m_data -= optlen;
  381.         m->m_len += optlen;
  382.         m->m_pkthdr.len += optlen;
  383.         ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
  384.     }
  385.     ip = mtod(m, struct ip *);
  386.     aligned_bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
  387.     *phlen = sizeof(struct ip) + optlen;
  388.     ip->ip_len += optlen;
  389.     return (m);
  390. }
  391.  
  392. /*
  393.  * Copy options from ip to jp,
  394.  * omitting those not copied during fragmentation.
  395.  */
  396. int
  397. ip_optcopy(ip, jp)
  398.     struct ip *ip, *jp;
  399. {
  400.     register u_char *cp, *dp;
  401.     int opt, optlen, cnt;
  402.  
  403.     cp = (u_char *)(ip + 1);
  404.     dp = (u_char *)(jp + 1);
  405.     cnt = (ip->ip_hl << 2) - sizeof (struct ip);
  406.     for (; cnt > 0; cnt -= optlen, cp += optlen) {
  407.         opt = cp[0];
  408.         if (opt == IPOPT_EOL)
  409.             break;
  410.         if (opt == IPOPT_NOP)
  411.             optlen = 1;
  412.         else
  413.             optlen = cp[IPOPT_OLEN];
  414.         /* bogus lengths should have been caught by ip_dooptions */
  415.         if (optlen > cnt)
  416.             optlen = cnt;
  417.         if (IPOPT_COPIED(opt)) {
  418.             bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
  419.             dp += optlen;
  420.         }
  421.     }
  422.     for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
  423.         *dp++ = IPOPT_EOL;
  424.     return (optlen);
  425. }
  426.  
  427. /*
  428.  * IP socket option processing.
  429.  */
  430. int
  431. ip_ctloutput(op, so, level, optname, mp)
  432.     int op;
  433.     struct socket *so;
  434.     int level, optname;
  435.     struct mbuf **mp;
  436. {
  437.     register struct inpcb *inp = sotoinpcb(so);
  438.     register struct mbuf *m = *mp;
  439.     register int optval = 0;
  440.     int error = 0;
  441.  
  442.     if (level != IPPROTO_IP)
  443.         error = EINVAL;
  444.     else switch (op) {
  445.  
  446.     case PRCO_SETOPT:
  447.         switch (optname) {
  448.         case IP_OPTIONS:
  449. #ifdef notyet
  450.         case IP_RETOPTS:
  451.             return (ip_pcbopts(optname, &inp->inp_options, m));
  452. #else
  453.             return (ip_pcbopts(&inp->inp_options, m));
  454. #endif
  455.  
  456.         case IP_TOS:
  457.         case IP_TTL:
  458.         case IP_RECVOPTS:
  459.         case IP_RECVRETOPTS:
  460.         case IP_RECVDSTADDR:
  461.             if (m->m_len != sizeof(int))
  462.                 error = EINVAL;
  463.             else {
  464.                 optval = *mtod(m, int *);
  465.                 switch (optname) {
  466.  
  467.                 case IP_TOS:
  468.                     inp->inp_ip.ip_tos = optval;
  469.                     break;
  470.  
  471.                 case IP_TTL:
  472.                     inp->inp_ip.ip_ttl = optval;
  473.                     break;
  474. #define    OPTSET(bit) \
  475.     if (optval) \
  476.         inp->inp_flags |= bit; \
  477.     else \
  478.         inp->inp_flags &= ~bit;
  479.  
  480.                 case IP_RECVOPTS:
  481.                     OPTSET(INP_RECVOPTS);
  482.                     break;
  483.  
  484.                 case IP_RECVRETOPTS:
  485.                     OPTSET(INP_RECVRETOPTS);
  486.                     break;
  487.  
  488.                 case IP_RECVDSTADDR:
  489.                     OPTSET(INP_RECVDSTADDR);
  490.                     break;
  491.                 }
  492.             }
  493.             break;
  494. #undef OPTSET
  495.  
  496.         default:
  497.             error = EINVAL;
  498.             break;
  499.         }
  500.         if (m)
  501.             (void)m_free(m);
  502.         break;
  503.  
  504.     case PRCO_GETOPT:
  505.         switch (optname) {
  506.         case IP_OPTIONS:
  507.         case IP_RETOPTS:
  508.             *mp = m = m_get(M_WAIT, MT_SOOPTS);
  509.             if (inp->inp_options) {
  510.                 m->m_len = inp->inp_options->m_len;
  511.                 aligned_bcopy(mtod(inp->inp_options, caddr_t),
  512.                     mtod(m, caddr_t), (unsigned)m->m_len);
  513.             } else
  514.                 m->m_len = 0;
  515.             break;
  516.  
  517.         case IP_TOS:
  518.         case IP_TTL:
  519.         case IP_RECVOPTS:
  520.         case IP_RECVRETOPTS:
  521.         case IP_RECVDSTADDR:
  522.             *mp = m = m_get(M_WAIT, MT_SOOPTS);
  523.             m->m_len = sizeof(int);
  524.             switch (optname) {
  525.  
  526.             case IP_TOS:
  527.                 optval = inp->inp_ip.ip_tos;
  528.                 break;
  529.  
  530.             case IP_TTL:
  531.                 optval = inp->inp_ip.ip_ttl;
  532.                 break;
  533.  
  534. #define    OPTBIT(bit)    (inp->inp_flags & bit ? 1 : 0)
  535.  
  536.             case IP_RECVOPTS:
  537.                 optval = OPTBIT(INP_RECVOPTS);
  538.                 break;
  539.  
  540.             case IP_RECVRETOPTS:
  541.                 optval = OPTBIT(INP_RECVRETOPTS);
  542.                 break;
  543.  
  544.             case IP_RECVDSTADDR:
  545.                 optval = OPTBIT(INP_RECVDSTADDR);
  546.                 break;
  547.             }
  548.             *mtod(m, int *) = optval;
  549.             break;
  550.  
  551.         default:
  552.             error = EINVAL;
  553.             break;
  554.         }
  555.         break;
  556.     }
  557.     return (error);
  558. }
  559.  
  560. /*
  561.  * Set up IP options in pcb for insertion in output packets.
  562.  * Store in mbuf with pointer in pcbopt, adding pseudo-option
  563.  * with destination address if source routed.
  564.  */
  565. #ifdef notyet
  566. int
  567. ip_pcbopts(optname, pcbopt, m)
  568.     int optname;
  569. #else
  570. int
  571. ip_pcbopts(pcbopt, m)
  572. #endif
  573.     struct mbuf **pcbopt;
  574.     register struct mbuf *m;
  575. {
  576.     register cnt, optlen;
  577.     register u_char *cp;
  578.     u_char opt;
  579.  
  580.     /* turn off any old options */
  581.     if (*pcbopt)
  582.         (void)m_free(*pcbopt);
  583.     *pcbopt = 0;
  584.     if (m == (struct mbuf *)0 || m->m_len == 0) {
  585.         /*
  586.          * Only turning off any previous options.
  587.          */
  588.         if (m)
  589.             (void)m_free(m);
  590.         return (0);
  591.     }
  592.  
  593. #ifndef    vax
  594.     if (m->m_len % sizeof(long))
  595.         goto bad;
  596. #endif
  597.     /*
  598.      * IP first-hop destination address will be stored before
  599.      * actual options; move other options back
  600.      * and clear it when none present.
  601.      */
  602.     if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
  603.         goto bad;
  604.     cnt = m->m_len;
  605.     m->m_len += sizeof(struct in_addr);
  606.     cp = mtod(m, u_char *) + sizeof(struct in_addr);
  607.     ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
  608.     aligned_bzero_const(mtod(m, caddr_t), sizeof(struct in_addr));
  609.  
  610.     for (; cnt > 0; cnt -= optlen, cp += optlen) {
  611.         opt = cp[IPOPT_OPTVAL];
  612.         if (opt == IPOPT_EOL)
  613.             break;
  614.         if (opt == IPOPT_NOP)
  615.             optlen = 1;
  616.         else {
  617.             optlen = cp[IPOPT_OLEN];
  618.             if (optlen <= IPOPT_OLEN || optlen > cnt)
  619.                 goto bad;
  620.         }
  621.         switch (opt) {
  622.  
  623.         default:
  624.             break;
  625.  
  626.         case IPOPT_LSRR:
  627.         case IPOPT_SSRR:
  628.             /*
  629.              * user process specifies route as:
  630.              *    ->A->B->C->D
  631.              * D must be our final destination (but we can't
  632.              * check that since we may not have connected yet).
  633.              * A is first hop destination, which doesn't appear in
  634.              * actual IP option, but is stored before the options.
  635.              */
  636.             if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
  637.                 goto bad;
  638.             m->m_len -= sizeof(struct in_addr);
  639.             cnt -= sizeof(struct in_addr);
  640.             optlen -= sizeof(struct in_addr);
  641.             cp[IPOPT_OLEN] = optlen;
  642.             /*
  643.              * Move first hop before start of options.
  644.              */
  645.             bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
  646.                 sizeof(struct in_addr));
  647.             /*
  648.              * Then copy rest of options back
  649.              * to close up the deleted entry.
  650.              */
  651.             ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
  652.                 sizeof(struct in_addr)),
  653.                 (caddr_t)&cp[IPOPT_OFFSET+1],
  654.                 (unsigned)cnt + sizeof(struct in_addr));
  655.             break;
  656.         }
  657.     }
  658.     if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
  659.         goto bad;
  660.     *pcbopt = m;
  661.     return (0);
  662.  
  663. bad:
  664.     (void)m_free(m);
  665.     return (EINVAL);
  666. }
  667.